﻿using LibNiconico.NiconicoApi.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace LibNiconico.NiconicoApi.Extentions
{
    internal static class XElementExtention
    {
        internal static int GetElementAsInt(this XElement element,string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsInt(value);
            },element, name);
        }

        internal static int GetValueAsInt(string value)
        {
            return value == null ? default(int) : int.Parse(value);
        }

        internal static long GetElementAsLong(this XElement element, string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsLong(value);
            }, element, name);
        }



        internal static long GetValueAsLong(string value)
        {
            return value == null ? default(long) : long.Parse(value);
        }

        internal static string GetElementAsString(this XElement element, string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsString(value);
            },element, name);
        }

        internal static string GetValueAsString(string value)
        {
            return value == null ? "" : value;
        }



        internal static Uri GetElementAsUri(this XElement element, string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsUri(value);
            }, element, name);
        }



       

        internal static Uri GetValueAsUri(string value)
        {
            return value == null || value == "" ? default(Uri) : new Uri(value);
        }

        internal static DateTime GetElementAsDateTime(this XElement element, string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsDateTime(value);
            }, element, name);
        }

        internal static DateTime GetValueAsDateTime(string value)
        {
            return value == null ? default(DateTime) : DateTime.Parse(value);
        }

        internal static bool GetElementAsBool(this XElement element, string name)
        {
            return GetElementFunc((value) =>
            {
                return GetValueAsBool(value);
            }, element, name);
        }

        internal static bool GetValueAsBool(string value)
        {
            return value == null ? default(bool) : (value == "1" || value == "true");
        }


        private static T GetElementFunc<T>(Func<string,T> func,XElement element,string name)
        {
            try
            {
                XElement child = element.Element(name);

                return func(child == null ? null : child.Value);

            }
            catch(Exception e)
            {
                throw NicoApiException.CreateXmlParseException(name,e);
            }
            
        }


        internal static int GetAttributeAsInt(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsInt(value);
            }, element, name);
        }

        internal static long GetAttributeAsLong(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsLong(value);
            }, element, name);
        }

        internal static string GetAttributeAsString(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsString(value);
            }, element, name);
        }

        internal static Uri GetAttributeAsUri(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsUri(value);
            }, element, name);
        }

        internal static DateTime GetAttributeAsDateTime(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsDateTime(value);
            }, element, name);
        }


        internal static bool GetAttributeAsBool(this XElement element, string name)
        {
            return GetAttributeFunc((value) =>
            {
                return GetValueAsBool(value);
            }, element, name);
        }



        internal static T GetAttributeFunc<T>(Func<string, T> func, XElement element, string name)
        {
            try
            {
                XAttribute attr = element.Attribute(name);

                return func(attr == null ? null : attr.Value);

            }
            catch (Exception e)
            {
                throw NicoApiException.CreateXmlParseException(name, e);
            }

        }


        internal static T Parse<T>(XElement element, XName name, Func<XElement,T> func)
        {
            if (element == null) return default(T);
            var rslts = from item in element.Descendants(name)
                        select func(item);

            if (rslts.Count() > 0)
            {
                var enumrator = rslts.GetEnumerator();
                enumrator.MoveNext();
                return enumrator.Current;
            }

            return default(T);

        }
    }
}
